#include "CPTokenMessage.hpp"
#include "../Parameters.hpp"

using namespace BFT::messages;

CPTokenMessage::CPTokenMessage (boost::shared_ptr<char> _tok , int _tok_size, uint32_t _seqNo, uint32_t _sender)
	: MacArrayMessage::MacArrayMessage (CP_TOKEN_MESSAGE, computeSize(_tok_size), _sender, BFT::Parameters::getOrderCount())
{
	seqNo = _seqNo;
	token_size = _tok_size;
	token = _tok;
	
	//get the message bytes and the offset
	boost::shared_ptr<char> bytes;
	int bytes_size;
	bytes = getBytes(bytes_size);
	int offset = getOffset();
	
	//set the sequence number
	*(uint32_t*)(bytes.get()+offset) = htonl(seqNo);
	offset += SEQUENCE_NUMBER_SIZE;
	
	//set the token size
	*(uint32_t*)(bytes.get()+offset) = htonl(_tok_size);
	offset += TOKEN_SIZE_SIZE;
	
	//set the token
	memcpy( (void *)(bytes.get()+offset) , (const void *)(token.get()) , token_size);
	offset += token_size;
}

CPTokenMessage::CPTokenMessage ( boost::shared_ptr<char> _bytes, int _bytes_size)
	:MacArrayMessage::MacArrayMessage (_bytes, _bytes_size)
{
	if (getTag()!=CP_TOKEN_MESSAGE)
	{
		fprintf(stderr,"trying to build a CP token message from the wrong bytes! expected tag %d, actual tag %d\n"
			,CP_TOKEN_MESSAGE,getTag());
		exit(71);	
	}
	
	//get the bytes and the offset
	int bytes_size;
	boost::shared_ptr<char> bytes = getBytes(bytes_size);
	unsigned int offset = getOffset();
	
	//read the sequence number
	seqNo = ntohl( *(uint32_t*)(bytes.get()+offset) );
	offset += SEQUENCE_NUMBER_SIZE;
	
	//read the size of the token
	token_size = ntohl( *(uint32_t*)(bytes.get()+offset) );
	offset += TOKEN_SIZE_SIZE;
	
	//read the token
	token.reset( (char*)malloc(token_size) , free );
	memcpy( (void*)(token.get()) , (const void *)(bytes.get()+offset) , token_size );
	offset += token_size;
	
	if (offset != bytes_size - getAuthenticationSize())
	{
		fprintf(stderr, "trying to build a CPTokenMessage from unvalid byte input. expeted offset: %d, actual offset: %d\n"
			,bytes_size - getAuthenticationSize(), offset );
		exit(72);	
	}
}

boost::shared_ptr<char> CPTokenMessage::getToken(int& _token_size)
{
	_token_size = token_size;
	return token;
}

bool CPTokenMessage::matches(boost::shared_ptr<CPTokenMessage> _other_cpt)
{
	int other_token_size;
	boost::shared_ptr<char> other_token = _other_cpt.get()->getToken(other_token_size);

	bool match = _other_cpt.use_count()!=0 && token_size == other_token_size && seqNo == _other_cpt.get()->getSequenceNumber();
	
	for(int i=0; i<token_size && match ; i++)
		match = token.get()[i] == other_token.get()[i];
		
	return match;
}

bool CPTokenMessage::equals(boost::shared_ptr<CPTokenMessage> _other_cpt)
{
	bool equal = _other_cpt.use_count() != 0 && MacArrayMessage::equals(_other_cpt) && matches(_other_cpt);
	return equal;
}

void CPTokenMessage::printInfo()
{
	fprintf(stdout,"CPTokenMessage information:\n");
	fprintf(stdout,"sequence number: %d\n",seqNo);
	fprintf(stdout,"token size: %d\n", token_size);
	fprintf(stdout,"token: ");
	for (int i=0; i<token_size; i++)
		fprintf(stdout,"|%02X",(unsigned char)token.get()[i]);
	fprintf(stdout,"\n");	
}
